/*
 * Created on 2006-8-3 上午01:29:47
 */
package cn.com.sbell.vss.csg.heartbeat;

import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Node;

import cn.com.sbell.vss.VssConstants;
import cn.com.sbell.vss.csg.vap.bean.AlarmMessage;
import cn.com.sbell.vss.csg.vsclient.util.AlarmDispatchGroup;

import cn.com.sbell.vss.csg.vap.util.VsInfo;
import cn.com.sbell.vss.csg.vap.util.VsInfoManager;



public class HeartBeatMonitor {
	private final static Log logger = LogFactory.getLog(HeartBeatMonitor.class); 
	
	private Map alarmTaskMap;
	private Timer monitorTimer;

	private HttpClient httpClient;
	
	private String cmsUrl;
	
	private static HeartBeatMonitor monitor ;
	
	public void init(){
		monitor= this;
	}
	public void destroy(){
		monitorTimer.cancel();
	}
	private HeartBeatMonitor(){
		alarmTaskMap = Collections.synchronizedMap(new HashMap());
		monitorTimer = new Timer(true);
	}
	
	public static HeartBeatMonitor getMonitorInstance(){
		return monitor;
	}
	
	public void update(HeartBeatMessage message){
		logger.debug("Receive Heartbeat: " + message);
		TimerTask task = (TimerTask)alarmTaskMap.get(message);
		checkNatChange((HeartBeatAlarmTask)task,message);
		if(task != null){
			task.cancel();
			task = new HeartBeatAlarmTask(message);
		}else{
			task = new HeartBeatAlarmTask(message);
			sendDisConnAlarm(message, true);
		}
		alarmTaskMap.put(message, task);
		monitorTimer.schedule(task, message.getExpireTime());
	}
	private void checkNatChange(HeartBeatAlarmTask task,HeartBeatMessage message){
		if(null==task||null==
				task.getMessage().getServerIp()){
			VsInfo vsInfo=VsInfoManager.getVsInfoManager().checkVsInfo(message.getServerId());
				if(null==vsInfo||!message.getServerIp().equalsIgnoreCase(vsInfo.getVsIp())){
					if(!updateVs(message)){
//						next time should try again
					message.setServerIp(null);
					}
					if(null!=vsInfo){
						VsInfoManager.getVsInfoManager().deleteVsInfo(message.getServerId());
					}
				}
		}else if(!message.getServerIp().equalsIgnoreCase(task.getMessage().getServerIp())){
			if(!updateVs(message)){
//				next time should try again
			message.setServerIp(null);
			}
			
				VsInfoManager.getVsInfoManager().deleteVsInfo(message.getServerId());
			
		}
	}
	private boolean updateVs(HeartBeatMessage message){
		NameValuePair[] pairs = new NameValuePair[] {
				new NameValuePair("deviceId", message.getServerId()), 
				new NameValuePair("ip", message.getServerIp())};
		
		PostMethod method = new PostMethod(cmsUrl + "/UpdateVSInfo");
		if(VssConstants.FRONT_TYPE_AH.equalsIgnoreCase(message.getServerType())){
			method = new PostMethod(cmsUrl + "/UpdateAHInfo");
		}
		method.addParameters(pairs);
		try {
			// Execute the method.
			int statusCode = httpClient.executeMethod(method);

			if (HttpStatus.SC_OK != statusCode) {
				logger.warn("PostMethod failed at UpdateVs(AH)Info: "
						+ method.getStatusLine());
			} else {
				String body = method.getResponseBodyAsString();
				Document doc = DocumentHelper.parseText(body);
				Node returnCodeByEMSNode = doc
						.selectSingleNode("/response/result/@code");
				if (!VssConstants.CODE_SUCCESS.equals(returnCodeByEMSNode
						.getText())) {
					logger.warn("UpdateVs(AH)Info : returnCodeByEMS ="
							+ returnCodeByEMSNode.getText());
				} else {
					return true;
				
				}
			}
			
		} catch (HttpException e) {
			logger.error("UpdateVs(AH)Info : HttpException!",e);
			
		} catch (IOException e) {
			logger.error("UpdateVs(AH)Info : IOException!",e);
			
		} catch (DocumentException e) {
			logger.error("UpdateVs(AH)Info : DocumentException!",e);
			
		} finally {
			method.releaseConnection();
		}
		return false;
	}
	
	public static void sendDisConnAlarm(HeartBeatMessage message, boolean elinimate){
		AlarmMessage msg = new AlarmMessage();
		msg.setAlarmType(AlarmMessage.TYPE_VSDISCONN);		
		msg.setDeviceId(message.getServerId());
		msg.setServerType(AlarmMessage.SERVER_VS);
		msg.setServerIp(message.getServerIp());
		msg.setEliminated(elinimate);
		msg.setAlarmCode(AlarmMessage.ALARMCODE_VSDISCONN);
		msg.setEventType(AlarmMessage.EVENTTYPE_DEVICEALARM);
//		added vondart
if((null!=message.getServerType())&&(AlarmMessage.SERVER_AH.equalsIgnoreCase(message.getServerType())))
	{
//			process AH
			msg.setAlarmType(AlarmMessage.TYPE_AHDISCONN);
			msg.setServerType(AlarmMessage.SERVER_AH);
			msg.setAlarmCode(AlarmMessage.ALARMCODE_AHDISCONN);
	}else
	{
//			process VS
	if(elinimate)
		{
//			if(null!=message.getServerId() && null!=message.getServerIp() && 0!=message.getPort())
//			{
//				VsInfoManager.getVsInfoManager()
//				.addVsInfo(new VsInfo(message.getServerId(),message.getServerIp(),new Integer(message.getPort())));
//			}
//			else
//			{
//				logger.debug("HeartBeatMonitor:VsInfoManager.getVsInfoManager().addVsInfo failed:"+msg.toString());
//			}
		}
		else
		{
			if(logger.isDebugEnabled()){
				logger.debug("HeartBeatHandler:deleteVSInfo:"+msg.toString());
				}
			VsInfoManager.getVsInfoManager().deleteVsInfo(message.getServerId());
		}
		
	}
		AlarmDispatchGroup.getAlarmDispatchGroup().addMessage(msg);
	}
	
	private class HeartBeatAlarmTask extends TimerTask {
		
		private HeartBeatMessage message;
		
		public HeartBeatAlarmTask(HeartBeatMessage message){
			this.message = message;
		}

		public void run() {
			alarmTaskMap.remove(message);
			sendDisConnAlarm(message, false);
		}

		public HeartBeatMessage getMessage() {
			return message;
		}

		public void setMessage(HeartBeatMessage message) {
			this.message = message;
		}
		
	}

	public HttpClient getHttpClient() {
		return httpClient;
	}

	public void setHttpClient(HttpClient httpClient) {
		this.httpClient = httpClient;
	}

	public String getCmsUrl() {
		return cmsUrl;
	}

	public void setCmsUrl(String cmsUrl) {
		this.cmsUrl = cmsUrl;
	}
	
	
	
}
